﻿using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Audio;

namespace Nirvana
{
    [CreateAssetMenu(fileName = "AudioItem", menuName = "Nirvana/Audio/AudioItem")]
    public sealed class AudioItem : ScriptableObject
    {
        private enum PickMode
        {
            [EnumLabel("Sequence Pick")]
            SequencePick,
            [EnumLabel("Shuffle Pick")]
            ShufflePick,
            [EnumLabel("Random Weight Pick")]
            RandomPick,
            [EnumLabel("Sequence Loop")]
            SequenceLoop,
            [EnumLabel("Shuffle Loop")]
            ShuffleLoop
        }

        [EnumLabel]
        [Tooltip("How to play a sub-item.")]
        [SerializeField]
        private PickMode playMode;

        [Tooltip("The audio sub-items.")]
        [SerializeField]
        private AudioSubItemData[] subItems;

        [Tooltip("The output audio mixer group.")]
        [SerializeField]
        private AudioMixerGroup mixerGroup;

        [Tooltip("The volume control for this audio item.")]
        [Range(0f, 1f)]
        [SerializeField]
        private float volume = 1f;

        [SerializeField]
        [Tooltip("The delay of this audio.")]
        private float delay;

        [Tooltip("The spatial blend, 0 means this audio is pure 2D.")]
        [SerializeField]
        [Range(0f, 1f)]
        private float spatialBlend;

        [SerializeField]
        [Tooltip("The play interval between two play.")]
        private float interval;

        [Tooltip("The max count of this item can play, 0 mean no limit.")]
        [SerializeField]
        private int maxCount;

        /// <summary>
        /// 多个音效资源归类到一个组里面：根据组的限制参数，控制不同音效的播放
        /// </summary>
        [SerializeField]
        [Tooltip("The group used to control the audio playing.")]
        private AudioGroup audioGroup;
        public float Delay { get { return this.delay; } }

        /// <summary>
        /// 存储洗牌打乱的数据
        /// </summary>
        private AudioSubItemData[] audioSubItemsShuffle;
        /// <summary>
        /// 当前audio播放数量
        /// </summary>
        private int curPlayerCount;
        /// <summary>
        /// 记录subitem已播放下标，
        /// </summary>
        private int curSubItemIndex;
        private float curTime;


#if UNITY_EDITOR
       // [InitializeOnLoadMethod]
        private void Init()
        {
            EditorApplication.playModeStateChanged += OnInit; 
        }

        private  void OnInit(PlayModeStateChange state)
        {
            this.curSubItemIndex = 0;
            this.curPlayerCount = 0;
            this.curTime = 0;
        }
        public void InitDefaultSubItem()
        {
            AudioSubItemData subitem = default(AudioSubItemData);
            subitem.Clear();
            if (this.subItems == null)
            {
                this.subItems = new AudioSubItemData[1];
                this.subItems[0] = subitem;
            }
            else
            {
                ArrayUtility.Add<AudioSubItemData>(ref this.subItems, subitem);
            }
        }
#endif

        public void PlaySubItem(int index,AudioSource audioSource)
        {
            AudioSubItemData subitem = this.subItems[index];
            InitAudioSource(audioSource, subitem);
            float _delay = this.Delay + subitem.GetDelay();
            audioSource.PlayDelayed(_delay);
        }

        public void Reset()
        {
            this.curSubItemIndex = 0;
            this.curTime = 0f;
            this.curPlayerCount = 0;
        }


        public void InitAudioSource(AudioSource source,AudioSubItemData item)
        {
            source.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
            source.transform.localScale = Vector3.one;
            source.clip = item.GetAudioClip();
            if(item.GetMixerGroup() != null)
            {
                source.outputAudioMixerGroup = item.GetMixerGroup();
            }
            else
            {
                source.outputAudioMixerGroup = this.mixerGroup;
            }

            source.volume = this.volume * item.GetVolume();
            source.pitch = item.GetPitch();
            source.time = item.GetStartAt();
            source.spatialBlend = this.spatialBlend;
        }

        public void Remove(IPlayerAudio audio)
        {
            this.curPlayerCount--;
            if (this.audioGroup != null) this.audioGroup.Remove(audio);
        }

        public IPlayerAudio GetAudioItem(AudioSourcePool pool)
        {
            if (this.subItems.Length == 0) return PlayerAudioBasic.Instance;
            //等待间隔
            if (Time.realtimeSinceStartup < this.curTime + this.interval) return PlayerAudioBasic.Instance;
            if (this.maxCount >0 && this.curPlayerCount >= this.maxCount) return PlayerAudioBasic.Instance;
            if (this.audioGroup != null && !this.audioGroup.IsStop()) return PlayerAudioBasic.Instance;

            this.curPlayerCount++;
            this.curTime = Time.realtimeSinceStartup;
            IPlayerAudio audio = null;
            switch (this.playMode)
            {
                case PickMode.SequencePick:
                    audio = this.GetSequencePick(pool);
                    break;
                case PickMode.ShufflePick:
                    audio = this.GetShufflePick(pool);
                    break;
                case PickMode.RandomPick:
                    audio = this.GetRandomWeightPick(pool);
                    break;
                case PickMode.SequenceLoop:
                    audio = this.GetSequenceLoop(pool);
                    break;
                case PickMode.ShuffleLoop:
                    audio = this.GetShuffleLoop(pool);
                    break;
                default:
                    audio = PlayerAudioBasic.Instance;
                    break;
            }

            if (this.audioGroup != null && audio != PlayerAudioBasic.Instance) this.audioGroup.Add(audio);
            return audio;
        }

        private IPlayerAudio GetSequencePick(AudioSourcePool pool)
        {
            if (this.curSubItemIndex >= this.subItems.Length) this.curSubItemIndex = 0;
            AudioSubItemData subItem = this.subItems[this.curSubItemIndex++];
            return new PlayerAudioDelay(pool,this,subItem,false);
        }

        /// <summary>
        /// 获取一个洗牌打乱过的aduio
        /// </summary>
        private IPlayerAudio GetShufflePick(AudioSourcePool pool)
        {
            if(this.audioSubItemsShuffle == null || this.audioSubItemsShuffle.Length != this.subItems.Length)
            {
                this.audioSubItemsShuffle = new AudioSubItemData[this.subItems.Length];
                for (int i = 0; i < this.subItems.Length; i++) this.audioSubItemsShuffle[i] = this.subItems[i];
                this.curSubItemIndex = 0;
                this.audioSubItemsShuffle.Shuffle<AudioSubItemData>();
            }

            if(this.curSubItemIndex >= this.subItems.Length)
            {
                this.curSubItemIndex = 0;
                this.audioSubItemsShuffle.Shuffle<AudioSubItemData>();
            }
            var subitem = this.audioSubItemsShuffle[this.curSubItemIndex++];
            return new PlayerAudioDelay(pool, this, subitem, false);
        }

        /// <summary>
        /// 根据随机权重值获取一个audio
        /// </summary>
        private IPlayerAudio GetRandomWeightPick(AudioSourcePool pool)
        {
            float weight = 0;
            foreach (var p in this.subItems) weight += p.GetWeight();
            if(Mathf.Approximately(weight, 0f))
            {
                int index = Random.Range(0, this.subItems.Length);
                var subitem = this.subItems[index];
                return new PlayerAudioDelay(pool, this, subitem, false);
            }
            float w = Random.Range(0f, weight);
            foreach(var p in this.subItems)
            {
                w -= p.GetWeight();
                if(w <=0f) return new PlayerAudioDelay(pool, this, p, false);
            }

            return PlayerAudioBasic.Instance;
        }

        private IPlayerAudio GetSequenceLoop(AudioSourcePool pool)
        {
            if(this.subItems.Length == 1)
            {
                var subitem = this.subItems[0];
                return new PlayerAudioDelay(pool, this, subitem, true);
            }

            var source = pool.Pop(this.name);
            source.loop = false;
            return new PlayerAudioSequence(this,pool,source,this.subItems);
        }
        /// <summary>
        /// 目前作空逻辑播放
        /// </summary>
        private IPlayerAudio GetShuffleLoop(AudioSourcePool pool)
        {
            return PlayerAudioBasic.Instance;
        }

    }
}

